package com.imyuanma.qingyun.common.config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * Spring Security 配置
 *
 * @author wangjy
 * @date 2022/07/09 15:17:45
 */
@Configuration
@EnableWebSecurity
public class QingYunSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DefaultLoginSuccessHandler defaultLoginSuccessHandler;
    @Autowired
    private DefaultLoginFailureHandler defaultLoginFailureHandler;
    @Autowired
    private DefaultSessionAuthFailureHandler defaultSessionAuthFailureHandler;
    @Autowired
    private DefaultInvalidSessionStrategy defaultInvalidSessionStrategy;
    @Autowired
    private DefaultSecurityContextRepository defaultSecurityContextRepository;
    @Autowired
    private DefaultAuthenticationEntryPoint defaultAuthenticationEntryPoint;
    @Autowired
    private DefaultAccessDeniedHandler defaultAccessDeniedHandler;
    @Autowired
    private DefaultLogoutSuccessHandler defaultLogoutSuccessHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(DefaultPasswordEncoder.newInstance("qingyun"));
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 不设置默认会返回响应头 X-Frame-Options: DENY, 表示拒绝加载iframe
        http.headers().frameOptions().disable();
        // 关闭csrf校验, 否则post请求会返回403
        http.csrf().disable();
        http.authorizeRequests()
                // 不需要登录的请求, "/lowcode/**"
                .antMatchers("/page/**", "/static/**", "/", "/error"
                        , "/login", "/sso/**"
                        , "/fs/file/image/**", "/fs/file/preview/**", "/fs/file/download", "/fs/file/transferFile"
                        , "/lowcode/online/html/**").permitAll()
                // 拦截的请求
                .anyRequest().authenticated()
        ;

        // 登录配置
        http.formLogin()
                .usernameParameter("account")
                .passwordParameter("password")
                .loginPage("/page/login.html")
                .loginProcessingUrl("/sso/login")
//                .defaultSuccessUrl("/")
                .successHandler(defaultLoginSuccessHandler)
                .failureHandler(defaultLoginFailureHandler)
                .permitAll();
//                .and().rememberMe()

        // 注销登录配置
        http.logout()
                .logoutUrl("/sso/logout")
                .logoutSuccessUrl("/page/login.html")
                .logoutSuccessHandler(defaultLogoutSuccessHandler)
                .permitAll();

        // 会话管理
        http.sessionManagement().disable()
//                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                // 这个有啥用还没搞明白
//                .sessionAuthenticationFailureHandler(defaultSessionAuthFailureHandler)
//                // 会话失效的处理策略
//                .invalidSessionStrategy(defaultInvalidSessionStrategy)
        ;
        //失效后跳转到登陆页面
//                .invalidSessionUrl("/page/login.html")
        //单用户登录，如果有一个登录了，同一个用户在其他地方登录将前一个剔除下线
        //.maximumSessions(1).expiredSessionStrategy(expiredSessionStrategy())
        //单用户登录，如果有一个登录了，同一个用户在其他地方不能登录
        //.maximumSessions(1).maxSessionsPreventsLogin(true) ;

        // 上下文资源库
        http.securityContext().securityContextRepository(defaultSecurityContextRepository);

        http.exceptionHandling()
                // 认证失败处理, 未登录访问需认证资源时触发
                .authenticationEntryPoint(defaultAuthenticationEntryPoint)
                // 访问拒绝处理, 无权限时触发
                .accessDeniedHandler(defaultAccessDeniedHandler);

    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 配置静态文件不需要认证
        web.ignoring().antMatchers("/page/**", "/static/**", "/favicon.**", "/fs_static/**");
    }
}
